package top.tenebrous.yzl.im.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import top.tenebrous.yzl.im.ImChatProcessor;
import top.tenebrous.yzl.im.analysis.Finder;
import top.tenebrous.yzl.im.contants.CommonConstants;
import top.tenebrous.yzl.im.context.ImContext;
import top.tenebrous.yzl.im.entity.ImWebSocketProperties;
import top.tenebrous.yzl.im.enums.ChatType;
import top.tenebrous.yzl.im.enums.MessageType;
import top.tenebrous.yzl.im.factory.message.MessageFactory;
import top.tenebrous.yzl.im.interceptor.ImWebsocketInterceptor;
import top.tenebrous.yzl.im.message.MessageBody;
import top.tenebrous.yzl.im.message.MessageNotice;
import top.tenebrous.yzl.im.model.ImClientUserBean;
import top.tenebrous.yzl.im.observer.AbstractChatRecord;
import top.tenebrous.yzl.im.utils.DateUtils;
import top.tenebrous.yzl.im.utils.WebSocketUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * websocket连接时，权限认证，session处理，群组查询等
 *
 * @author yazhang6
 */
@Slf4j
@Component
public class WebSocketChainInfoMessageHandler implements MessageHandler<MessageBody>, InitializingBean {

    @Autowired
    private MessageFactory messageFactory;

    @Autowired
    private ImWebSocketProperties webSocketProperties;

    @Autowired
    private AbstractChatRecord<MessageNotice> chatRecord;

    @Autowired
    private ImContext imContext;

    @Resource
    private ImChatProcessor imChatProcessor;

    @Override
    public void execute(WebSocketSession session, MessageBody message) {
        // 敏感词过滤
        String content = message.getContent();

        // 校验是否开启敏感词过滤
        if (webSocketProperties.isEnableOpenSensitiveWord()) {
            content = Finder.replace(content);
        }

        // 查询发送者基本信息
        ImClientUserBean userBean = imChatProcessor.takeAfterChatUserInfo(message.getFrom());
        if (Objects.isNull(userBean)) {
            throw new RuntimeException("用户不存在");
        }

        MessageNotice messageNotice = new MessageNotice();
        BeanUtils.copyProperties(message, messageNotice);
        messageNotice.setCreateDate(DateUtils.dateToString(new Date(), DateUtils.DATE_FORMAT_DATE_TIME));
        messageNotice.setContent(content);
        messageNotice.setFromImageUrl(userBean.getImageUrl());
        messageNotice.setFromName(userBean.getUserName());
        Long quoteId = parseQuote(message.getExtras());
        messageNotice.setQuoteId(quoteId);
        messageNotice.setHasQuote(Objects.nonNull(quoteId));
        messageNotice.setQuoteContent(parseQuoteContent(message.getExtras()));
        messageNotice.setMessageId(parseMessageId(message.getExtras()));
        List<MessageNotice> records = new ArrayList<>();
        // 判断是否为群发消息
        if (Objects.equals(message.getChatType(), ChatType.PUBLIC_CHAT_TYPE.getCode())) {
            String groupId = message.getGroupId();
            WebSocketSession userSession = null;
            List<WebSocketSession> sessionList = new ArrayList<>();
            // 获取组下所有session
            // TODO 新建群聊时，无群组session，待优化
            List<WebSocketSession> sessionGroup = WebSocketUtils.getSessionGroup(groupId);
            String extras = message.getExtras();
            String newGroupFlag = "0";
                JSONObject jsonObject = JSONObject.parseObject(extras);
            if (Objects.nonNull(jsonObject)) {
                newGroupFlag = jsonObject.getString("newGroupFlag");
            }
            if (StringUtils.isNotBlank(newGroupFlag) && "1".equals(newGroupFlag)) {
                // 群聊可能刚刚创建，需要获取用户session
                userSession = WebSocketUtils.getSession(message.getTo());
                if (Objects.nonNull(userSession)) {
                    // 将当前用户加入群聊
                    WebSocketUtils.addSession(userSession, ImClientUserBean.builder().userId(message.getTo()).build(),
                        Collections.singletonList(groupId));
                    sessionList.add(userSession);
                }

            } else {
                // 获取组下所有session
                sessionGroup = WebSocketUtils.getSessionGroup(groupId);
                if (CollUtil.isNotEmpty(sessionGroup)) {
                    sessionList.addAll(sessionGroup);
                    // 去除发送者本身
                    sessionList.remove(session);
                }
            }

            List<Map.Entry<ImWebsocketInterceptor, Integer>> sortList = imContext.handlerInterceptorSorted();
            // 执行扩展拦截
            for (Map.Entry<ImWebsocketInterceptor, Integer> entry : sortList) {
                String data = entry.getKey().beforeImWebSocketOnSendProcessor(messageNotice.getContent());
                messageNotice.setContent(data);
            }
            try {
                WebSocketUtils.sendGroup(sessionList, messageNotice.getType(), messageNotice);
            } catch (IOException e) {
                log.error("{} 群发消息异常:{}", CommonConstants.LOG_PREFIX, e);
            }

            // 持久化消息
            List<WebSocketSession> sessionGroupList = WebSocketUtils.getSessionGroup(groupId);
            if (CollUtil.isNotEmpty(sessionGroupList)) {
                // 持久化消息 不能排除自己
                for (WebSocketSession socketSession : sessionGroupList) {
                    MessageNotice message1 = new MessageNotice();
                    BeanUtils.copyProperties(messageNotice, message1);
                    message1.setTo(WebSocketUtils.getUserIdBySession(socketSession));
                    if (StringUtils.isBlank(WebSocketUtils.getUserIdBySession(socketSession))) {
                        // 接收者不在线
                        message1.setEnableRead(0);
                    }
                    records.add(message1);
                }
            }

            // 通知观察者
            chatRecord.notifyObserver(records);

            // TODO 推送列表信息
            for (WebSocketSession webSocketSession : sessionList) {
                pushMessageListInfo(webSocketSession, messageNotice);
            }

        } else {
            // 获取接收者session
            WebSocketSession socketSession = WebSocketUtils.getSession(message.getTo());
            if (Objects.isNull(socketSession)) {
                log.warn("{} 服务端--->消息接收者[{}]不在线或不存在 读取状态为未读", CommonConstants.LOG_PREFIX,
                    message.getTo());
                // 接收者不在线
                messageNotice.setEnableRead(0);
            }
            List<Map.Entry<ImWebsocketInterceptor, Integer>> sortList = imContext.handlerInterceptorSorted();
            // 执行扩展拦截
            for (Map.Entry<ImWebsocketInterceptor, Integer> entry : sortList) {
                String data = entry.getKey().beforeImWebSocketOnSendProcessor(messageNotice.getContent());
                messageNotice.setContent(data);
            }
            try {
                WebSocketUtils.send(socketSession, messageNotice.getType(), messageNotice);
            } catch (IOException e) {
                log.error("{} 发送私聊消息异常:{}", CommonConstants.LOG_PREFIX, e);
            }
            records.add(messageNotice);
            // 通知观察者
            chatRecord.notifyObserver(records);

            // TODO 推送列表信息
            pushMessageListInfo(socketSession, messageNotice);
        }

    }

    private String parseMessageId(String extras) {
        if (StrUtil.isBlank(extras)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(extras);
        return jsonObject.getString("messageId");
    }

    private String parseQuoteContent(String extras) {
        if (StrUtil.isBlank(extras)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(extras);
        return jsonObject.getString("quoteContent");
    }

    private Long parseQuote(String extras) {
        if (StrUtil.isBlank(extras)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(extras);
        return jsonObject.getLong("quoteId");
    }

    /**
     * 推送消息列表
     *
     * @param socketSession
     *     接收者session
     * @param messageNotice
     *     消息内容
     */
    private void pushMessageListInfo(WebSocketSession socketSession, MessageNotice messageNotice) {
        messageFactory.getInstance(MessageType.LIST).execute(socketSession, messageNotice);
    }

    @Override
    public String getType() {
        return MessageType.PUT.getCode();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        messageFactory.register(MessageType.PUT, this);
    }
}
